package zdream.pmfield.test.stage.effect;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicBoolean;

import zdream.pmfield.core.Result;
import zdream.pmfield.data.foe.Foe;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.data.foe.Type;
import zdream.pmfield.stage.StageBuilderForTest;
import zdream.pmfield.stage.StageWrapper;
import zdream.pmfield.stage.message.ActionRequestMessage;
import zdream.pmfield.stage.message.RollReportMessage;
import zdream.pmfield.stage.message.FoeAddBuffMessage;
import zdream.pmfield.stage.message.FoeRemoveBuffMessage;
import zdream.pmfield.stage.message.TurnStartMessage;
import zdream.pmfield.stage.object.FoeActor;
import zdream.pmfield.stage.object.StageMove;
import zdream.pmfield.storage.FoeTemplateStorage;
import zdream.pmfield.test.utils.ResourceConstant;
import zdream.pmfield.test.utils.StageConstant;

import static org.junit.Assert.*;

/**
 * @author Zdream
 * @date 2023-12-04
 * @since 0.0.1
 */
public class WetBuffCase {
	FoeTemplateStorage storage;

	@Before
	public void before() {
		storage = new FoeTemplateStorage();
		storage.load();
		storage.loadMovesInResource(ResourceConstant.RES_PATH_TEST_MOVES_JSON);
	}

	@Test
	public void testWetEffect() {
		MoveTemplate wetMove = storage.findMoveById(10000017, 1);
		assertEquals(wetMove.name, "肯定潮湿");
		MoveTemplate paralysisMove = storage.findMoveById(10000012, 1);
		assertEquals(paralysisMove.name, "肯定麻痹");
		MoveTemplate normalMove = storage.findMoveById(10000015, 1);
		assertEquals(normalMove.name, "无效果");

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(30)
				.withMove(wetMove)
				.withMove(paralysisMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(25))
				.withLevel(30)
				.withMove(normalMove)
				.build();
		assertArrayEquals(foe2.template.types, new Type[] {Type.ELECTRIC});

		final StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.buildWrapper();

		System.out.println("TEST 1: apply wet");
		AtomicBoolean wetRequest = new AtomicBoolean(false);
		AtomicBoolean wetApplied = new AtomicBoolean(false);
		AtomicBoolean checked = new AtomicBoolean(false);
		float[] buffAppliedTime = new float[1];
		float[] buffFirstRollCheckTime = new float[1];
		float[] buffRemovedTime = new float[1];

		wrapper.printBeforeHandleMessage();
		wrapper.onActionRequestForAll(wrapper.createDefaultController().withActionChecker(action -> {
			if (action.move.move == wetMove) {
				wetRequest.set(true);
			}
		}));
		wrapper.onMessage(FoeAddBuffMessage.class, message -> {
			assertTrue(message.buff.is(StageConstant.BUFF_WET));
			assertTrue(message.success);
			wetApplied.set(true);
			buffAppliedTime[0] = wrapper.now();
		});
		wrapper.onMessage(TurnStartMessage.class, message -> {
			if (!wetRequest.get()) {
				return;
			}
			assertTrue(wetApplied.get());
			checked.set(true);
		});

		wrapper.runUntil(stage0 -> checked.get());
		assertTrue(checked.get());

		System.out.println("TEST 2: 已经潮湿的无法再潮湿");
		wrapper.clearOnMessageHooks();

		wetRequest.set(false);
		wetApplied.set(false);
		checked.set(false);

		wrapper.onActionRequestForAll(wrapper.createDefaultController().withActionChecker(action -> {
			if (action.move.move == wetMove) {
				wetRequest.set(true);
			}
		}));
		wrapper.onMessage(FoeAddBuffMessage.class, message -> {
			assertTrue(message.buff.is(StageConstant.BUFF_WET));
			assertFalse(message.success);
			assertTrue(message.rejectBy.is(StageConstant.BUFF_WET));
			wetApplied.set(true);
		});
		wrapper.onMessage(TurnStartMessage.class, message -> {
			if (!wetRequest.get()) {
				return;
			}
			assertTrue(wetApplied.get());
			checked.set(true);
		});

		wrapper.runUntil(stage0 -> checked.get());
		assertTrue(checked.get());

		System.out.println("TEST 3: wet 状态是, 麻痹免疫失效");
		wrapper.clearOnMessageHooks();
		checked.set(false);

		AtomicBoolean paralysisRequest = new AtomicBoolean(false);

		wrapper.onDefaultActionRequest(foe2);
		wrapper.onMessage(ActionRequestMessage.class, message -> {
			final FoeActor foe = message.foe;
			if (foe.foe != foe1) {
				return;
			}

			final StageMove stageMove = foe.attackMoves.get(1);
			assertEquals(stageMove.move.id, 10000012);
			final Result commit = message.createReplyTemplate()
					.withMove(stageMove)
					.withTarget(foe2)
					.commit();
			assertTrue(commit.errorMessage, commit.success);
			paralysisRequest.set(true);
		});
		wrapper.onMessage(FoeAddBuffMessage.class, message -> {
			assertTrue(message.buff.is(StageConstant.BUFF_PARALYSIS));
			assertTrue(message.success);
			assertTrue(paralysisRequest.get());
			checked.set(true);
		});

		wrapper.runUntil(stage0 -> checked.get());
		assertTrue(checked.get());

		System.out.println("TEST 4: wet 状态会随时间消失");

		wrapper.clearOnMessageHooks();
		checked.set(false);

		wrapper.onDefaultActionRequest();
		wrapper.onMessage(RollReportMessage.class, message -> {
			if (message.foe.foe == foe1) {
				return;
			}
			if (StageConstant.BUFF_WET.equals(message.title)) {
				buffFirstRollCheckTime[0] = wrapper.now();
			}
		});
		wrapper.onMessage(FoeRemoveBuffMessage.class, message -> {
			if (message.buff.not(StageConstant.BUFF_WET)) {
				return;
			}
			assertEquals(message.foe.foe, foe2);
			assertTrue(message.buff.is(StageConstant.BUFF_WET));
			buffRemovedTime[0] = wrapper.now();
			checked.set(true);
		});

		wrapper.runUntil(stage0 -> checked.get());
		assertTrue(checked.get());
		assertTrue(buffFirstRollCheckTime[0] >= buffAppliedTime[0] + 3);
		assertTrue(buffRemovedTime[0] >= buffFirstRollCheckTime[0]);
	}

	@Test
	public void testWaterTypeBlockWetBuff() {
		MoveTemplate wetMove = storage.findMoveById(10000017, 1);
		assertEquals(wetMove.name, "肯定潮湿");
		MoveTemplate normalMove = storage.findMoveById(10000010, 1);
		assertEquals(normalMove.name, "肯定成功");

		Foe foe1 = Foe.builder(storage.findFoeById(4))
				.withLevel(20)
				.withMove(wetMove)
				.build();
		Foe foe2 = Foe.builder(storage.findFoeById(54))
				.withLevel(54)
				.withMove(normalMove)
				.build();
		assertArrayEquals(foe2.template.types, new Type[] {Type.WATER});
		StageWrapper wrapper = StageBuilderForTest.builder()
				.putFoeToOneSide(foe1)
				.putFoeToAnotherSide(foe2)
				.withStorage(storage)
				.buildWrapper();

		wrapper.printBeforeHandleMessage();
		AtomicBoolean checked = new AtomicBoolean(false);

		wrapper.onDefaultActionRequest();
		wrapper.onMessage(FoeAddBuffMessage.class, message -> {
			// 潮湿效果对水系无效
			assertTrue(message.buff.is(StageConstant.BUFF_WET));
			assertFalse(message.success);
			assertNotNull(message.rejectBy);
			assertTrue(message.rejectBy.is(StageConstant.BUFF_TYPE));
			checked.set(true);
		});
		wrapper.runUntil(s -> checked.get());

		assertTrue(checked.get());
	}
}
